package me.aartikov.alligator.navigators;


import me.aartikov.alligator.animations.AnimationData;
import me.aartikov.alligator.animations.TransitionAnimation;
import me.aartikov.alligator.exceptions.AbilityResolvingException;
import me.aartikov.alligator.exceptions.NavigationException;
import me.aartikov.alligator.exceptions.ScreenRegistrationException;
import me.aartikov.alligator.listeners.TransitionListener;
import me.aartikov.alligator.TransitionType;
import me.aartikov.alligator.animations.providers.TransitionAnimationProvider;
import me.aartikov.alligator.destinations.AbilityDestination;
import me.aartikov.alligator.helpers.AbilityHelper;
import me.aartikov.alligator.helpers.ScreenResultHelper;
import me.aartikov.alligator.navigationfactories.NavigationFactory;
import me.aartikov.alligator.util.Log;
import me.aartikov.alligator.Screen;
import me.aartikov.alligator.ScreenResult;
import me.aartikov.alligator.AbilityStack;
import me.aartikov.alligator.DestinationType;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;

public class DefaultAbilityNavigator implements AbilityNavigator {

    public final static String ISLIMITANIMATION = "isLimitAnimation";

    private Ability mAbility;


    private NavigationFactory mNavigationFactory;


    private AbilityHelper mActivityHelper;


    private ScreenResultHelper mScreenResultHelper;


    private TransitionListener mTransitionListener;


    private TransitionAnimationProvider mAnimationProvider;

    public DefaultAbilityNavigator(Ability activity,
                                   NavigationFactory navigationFactory,
                                   TransitionListener transitionListener,
                                   TransitionAnimationProvider animationProvider) {
        mAbility = activity;
        mNavigationFactory = navigationFactory;
        mActivityHelper = new AbilityHelper(activity);
        mScreenResultHelper = new ScreenResultHelper(mNavigationFactory);
        mTransitionListener = transitionListener;
        mAnimationProvider = animationProvider;
    }

    @Override
    public boolean goForward(Screen screen,
                             AbilityDestination destination,
                             AnimationData animationData) throws NavigationException {

        Class<? extends me.aartikov.alligator.Screen> screenClassFrom = mNavigationFactory.getScreenClass(mAbility);
        Class<? extends me.aartikov.alligator.Screen> screenClassTo = screen.getClass();

        Intent intent = destination.createIntent(mAbility, screen, screenClassFrom);
        if (!mActivityHelper.resolve(intent)) {
            throw new AbilityResolvingException(screen);
        }

        intent.setParam(AbilityStack.STARTSTATE, AbilityStack.NORMOL);
        TransitionAnimation animation = getAnimation(TransitionType.FORWARD, screenClassFrom, screenClassTo, animationData);

        if (destination.getScreenResultClass() != null) {
            mActivityHelper.startForResult(intent, destination.getRequestCode(), animation);
        } else {
            mActivityHelper.start(intent, animation);
        }

        callTransitionListener(TransitionType.FORWARD, screenClassFrom, screenClassTo);
        return true;
    }


    @Override
    public boolean replace(Screen screen,
                           AbilityDestination destination,
                           AnimationData animationData) throws NavigationException {

        Class<? extends me.aartikov.alligator.Screen> previousScreenClass = mNavigationFactory.getPreviousScreenClass(mAbility);
        Intent intent = destination.createIntent(mAbility, screen, previousScreenClass);

        if (!mActivityHelper.resolve(intent)) {
            throw new AbilityResolvingException(screen);
        }

        intent.setParam(AbilityStack.STARTSTATE, AbilityStack.REPLACE);
        Class<? extends me.aartikov.alligator.Screen> screenClassFrom = mNavigationFactory.getScreenClass(mAbility);
        Class<? extends me.aartikov.alligator.Screen> screenClassTo = screen.getClass();
        TransitionAnimation animation = getAnimation(TransitionType.REPLACE, screenClassFrom, screenClassTo, animationData);


        mActivityHelper.start(intent, animation);
        mActivityHelper.finish(animation);
        callTransitionListener(TransitionType.REPLACE, screenClassFrom, screenClassTo);

        return true;
    }

    @Override
    public boolean reset(Screen screen,
                         AbilityDestination destination,
                         AnimationData animationData) throws NavigationException {

        Intent intent = destination.createIntent(mAbility, screen, null);
//		intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

        if (!mActivityHelper.resolve(intent)) {
            throw new AbilityResolvingException(screen);
        }


        Class<? extends Screen> screenClassFrom = mNavigationFactory.getScreenClass(mAbility);
        Class<? extends Screen> screenClassTo = screen.getClass();
        TransitionAnimation animation = getAnimation(TransitionType.RESET, screenClassFrom, screenClassTo, animationData);

        intent.setParam(AbilityStack.STARTSTATE, AbilityStack.RESET);
        mActivityHelper.start(intent, animation);

        callTransitionListener(TransitionType.RESET, screenClassFrom, screenClassTo);
        return true;
    }

    @Override
    public boolean goBack(ScreenResult screenResult,
                          AnimationData animationData) throws NavigationException {

        Log.i("DefaultActivityNavigator.goBack([screenResult, animationData]):134   " + (screenResult != null));
        if (screenResult != null) {
            mScreenResultHelper.setActivityResult(mAbility, screenResult);
        } else {

            Class<? extends Screen> screenClassFrom = mNavigationFactory.getScreenClass(mAbility);
            Class<? extends Screen> screenClassTo = mNavigationFactory.getPreviousScreenClass(mAbility);
            TransitionAnimation animation = getAnimation(TransitionType.BACK, screenClassFrom, screenClassTo, animationData);

            mActivityHelper.finish(animation);
            callTransitionListener(TransitionType.BACK, screenClassFrom, screenClassTo);
        }
        return true;
    }


    @Override
    public boolean goBackTo(Class<? extends Screen> screenClass,
                            AbilityDestination destination,
                            ScreenResult screenResult,
                            AnimationData animationData) throws NavigationException {



        Intent intent = destination.createEmptyIntent(mAbility, screenClass);
        if (intent == null) {
            throw new ScreenRegistrationException("Can't create intent for a screen " + screenClass.getSimpleName());
        }
//		intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        if (screenResult != null) {
            mScreenResultHelper.setResultToIntent(intent, mAbility, screenResult);
        }

        intent.setParam(AbilityStack.STARTSTATE, AbilityStack.BACKTO);
        Class<? extends me.aartikov.alligator.Screen> screenClassFrom = mNavigationFactory.getScreenClass(mAbility);
        TransitionAnimation animation = getAnimation(TransitionType.BACK, screenClassFrom, screenClass, animationData);
        mActivityHelper.start(intent, animation);
        callTransitionListener(TransitionType.BACK, screenClassFrom, screenClass);
        return true;
    }


    private TransitionAnimation getAnimation(TransitionType transitionType,
                                             Class<? extends me.aartikov.alligator.Screen> screenClassFrom,
                                             Class<? extends me.aartikov.alligator.Screen> screenClassTo,
                                             AnimationData animationData) {

        if (screenClassFrom == null || screenClassTo == null) {
            return TransitionAnimation.DEFAULT;
        } else {
            return mAnimationProvider.getAnimation(transitionType, DestinationType.ACTIVITY, screenClassFrom, screenClassTo, animationData);
        }
    }

    private void callTransitionListener(TransitionType transitionType,
                                        Class<? extends me.aartikov.alligator.Screen> screenClassFrom,
                                        Class<? extends me.aartikov.alligator.Screen> screenClassTo) {
        mTransitionListener.onScreenTransition(transitionType, DestinationType.ACTIVITY, screenClassFrom, screenClassTo);
    }
}
